package com.dag.account.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dag.account.api.dto.withdraw.ApplyWithdrawReqDTO;
import com.dag.account.api.dto.withdraw.ApplyWithdrawRespDTO;
import com.dag.account.api.dto.withdraw.AuditingDTO;
import com.dag.account.api.dto.withdraw.MarkTransferredDTO;
import com.dag.account.constants.*;
import com.dag.account.dao.entity.Account;
import com.dag.account.dao.entity.Member;
import com.dag.account.dao.entity.TradeRecord;
import com.dag.account.dao.entity.WithdrawBill;
import com.dag.account.dao.mapper.WithdrawBillMapper;
import com.dag.account.service.*;
import com.dag.account.utils.TradeUtils;
import com.dag.common.exception.BusinessRuntimeException;
import com.dag.seqno.Sequence;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 提现管理
 *
 * @author 孙建
 * @since 2020-05-30
 */
@Slf4j
@Service
public class WithdrawBillServiceImpl extends ServiceImpl<WithdrawBillMapper, WithdrawBill> implements IWithdrawBillService {

    @Autowired
    private IAccountService accountService;
    @Autowired
    private IMemberService memberService;
    @Autowired
    private ITradeRecordService tradeRecordService;
    @Autowired
    private IFundPoolService fundPoolService;
    @Autowired
    private Sequence sequence;

    /**
     * 申请提现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApplyWithdrawRespDTO applyWithdraw(ApplyWithdrawReqDTO applyWithdrawReqDTO) {
        Account account = accountService.getById(applyWithdrawReqDTO.getAccountId());
        BigDecimal applyAmount = applyWithdrawReqDTO.getAmount();
        // 校验提现逻辑
        ApplyWithdrawRespDTO applyWithdrawRespDTO = validateWithdraw(applyWithdrawReqDTO, account);
        // 校验通过
        if (applyWithdrawRespDTO.isSuccess()) {
            // 提现金额冻结
            accountService.freeze(account, applyAmount, applyWithdrawReqDTO.getMemberName());
            // 生成提现记录
            WithdrawBill withdrawBill = saveWithdrawRecord(applyWithdrawReqDTO, account);
            applyWithdrawRespDTO.setWithdrawId(withdrawBill.getId());
            applyWithdrawRespDTO.setWithdrawNo(withdrawBill.getWithdrawNo());

            // 生成交易记录
            saveWithdrawTradeRecord(withdrawBill);
        }
        return applyWithdrawRespDTO;
    }


    /**
     * 提现审核
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditing(AuditingDTO auditingDTO) {
        WithdrawBill withdrawBill = getById(auditingDTO.getWithdrawBillId());
        if (withdrawBill == null) {
            throw new BusinessRuntimeException("提现申请不存在");
        }else  if(withdrawBill.getStatus() != WithdrawStatusEnum.UNDERWAY.getIndex()){
            throw new BusinessRuntimeException("提现申请当前状态不允许审核");
        }

        Integer status = auditingDTO.getStatus();
        if (status == WithdrawStatusEnum.AGREE.getIndex()) {
            log.debug("提现审核通过");
        } else if (status == WithdrawStatusEnum.REFUSE.getIndex()) {
            log.debug("提现审核拒绝");
            // 将提现金额解冻
            Account account = accountService.getById(withdrawBill.getAccountId());
            accountService.unfreeze(account, withdrawBill.getAmount(), auditingDTO.getOperatorName());

            // 更新交易记录状态为关闭
            TradeRecord tradeRecord = tradeRecordService.queryByTradeVoucherNo(withdrawBill.getWithdrawNo(),
                    TradeTypeEnum.WITHDRAWAL.getIndex(), FundFlowTypeEnum.PAY.getIndex(), TradeStatusEnum.TRADE_STATUS_TRADING.getIndex());
            tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_CLOSE.getIndex());
            tradeRecord.setUpdaterId(auditingDTO.getOperatorId());
            tradeRecord.setRemarks(auditingDTO.getInspectRemark());
            tradeRecordService.updateById(tradeRecord);
        } else {
            throw new BusinessRuntimeException("无效的审核状态");
        }

        // 更新审核状态
        withdrawBill.setStatus(status);
        withdrawBill.setInspectTime(new Date());
        withdrawBill.setInspectRemark(auditingDTO.getInspectRemark());
        withdrawBill.setUpdaterId(auditingDTO.getOperatorId());
        updateById(withdrawBill);
    }


    /**
     * 标记为已转账
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void markTransferred(MarkTransferredDTO markTransferredDTO) {
        WithdrawBill withdrawBill = getById(markTransferredDTO.getWithdrawBillId());
        if (withdrawBill == null) {
            throw new BusinessRuntimeException("提现申请不存在");
        }

        Integer status = withdrawBill.getStatus();
        BigDecimal amount = withdrawBill.getAmount();
        String operatorName = markTransferredDTO.getOperatorName();
        // 提现单当前状态为审核通过或支付中时 才会选择更新提现单和交易单状态
        if (status == WithdrawStatusEnum.AGREE.getIndex() || status == WithdrawStatusEnum.PAY_UNDERWAY.getIndex()) {
            // 查询账户信息
            Account account = accountService.getById(withdrawBill.getAccountId());
            //查询交易单信息
            TradeRecord tradeRecord = tradeRecordService.queryByTradeVoucherNo(withdrawBill.getWithdrawNo(),
                    TradeTypeEnum.WITHDRAWAL.getIndex(), FundFlowTypeEnum.PAY.getIndex(), TradeStatusEnum.TRADE_STATUS_TRADING.getIndex());

            //标记是否更新交易单状态
            boolean updateTrade = true;
            //提现失败
            if (markTransferredDTO.getStatus() == WithdrawStatusEnum.FAIL.getIndex()) {
                // 将提现金额解冻
                accountService.unfreeze(account, amount, operatorName);
                // 改变交易记录状态为关闭
                tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_CLOSE.getIndex());

            } else if (markTransferredDTO.getStatus() == WithdrawStatusEnum.SUCCESS.getIndex()) {
                //提现成功

                //将提现金额解冻并扣除
                accountService.unfreezeDeduction(account, amount, operatorName);
                // 资金池扣减
                fundPoolService.deduction(amount, operatorName);

                //改变交易记录状态为成功
                tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_SUCCESS.getIndex());
            } else if (markTransferredDTO.getStatus() == WithdrawStatusEnum.PAY_UNDERWAY.getIndex()) {
                //如果状态为支付中，只改提现单状态，不改交易单状态
                updateTrade = false;
            }

            // 更新提现状态
            withdrawBill.setStatus(markTransferredDTO.getStatus());
            withdrawBill.setTransferTime(new Date());
            withdrawBill.setTransferRemark(markTransferredDTO.getTransferRemark());
            withdrawBill.setUpdaterId(markTransferredDTO.getOperatorId());
            updateById(withdrawBill);

            if (updateTrade) {
                // 更新交易记录状态
                tradeRecord.setRemarks(markTransferredDTO.getTransferRemark());
                tradeRecord.setUpdaterId(markTransferredDTO.getOperatorId());
                tradeRecordService.updateById(tradeRecord);
            }

        } else {
            throw new BusinessRuntimeException("当前状态不允许进行转账");
        }
    }


    /**
     * 生成提现记录
     */
    private WithdrawBill saveWithdrawRecord(ApplyWithdrawReqDTO applyWithdrawReqDTO, Account account) {
        WithdrawBill withdrawBill = new WithdrawBill();
        withdrawBill.setWithdrawNo(sequence.getFixedLengthSeqNo("acc_withdraw_bill", 8, "W"));
        withdrawBill.setMemberId(account.getMemberId());
        withdrawBill.setMemberName(applyWithdrawReqDTO.getMemberName());
        withdrawBill.setAccountId(account.getId());
        withdrawBill.setAccountType(account.getAccountType());
        withdrawBill.setAccountTypeName(account.getAccountTypeName());
        withdrawBill.setAmount(applyWithdrawReqDTO.getAmount());
        withdrawBill.setApplyRemark(applyWithdrawReqDTO.getApplyRemark());
        withdrawBill.setApplyTime(new Date());

        Integer withdrawChannel = applyWithdrawReqDTO.getWithdrawChannel();
        if (withdrawChannel == WithdrawChannelEnum.BANK_CARD.getIndex()) {
            withdrawBill.setBankName(applyWithdrawReqDTO.getBankName());
            withdrawBill.setCardNo(applyWithdrawReqDTO.getCardNo());
            withdrawBill.setSubBankName(applyWithdrawReqDTO.getSubBankName());
            withdrawBill.setOpenAccountName(applyWithdrawReqDTO.getOpenAccountName());
        } else {
            withdrawBill.setOtherAccountName(applyWithdrawReqDTO.getOtherAccountName());
            withdrawBill.setOtherAccountNo(applyWithdrawReqDTO.getOtherAccountNo());
            withdrawBill.setOtherAccountTypeName(applyWithdrawReqDTO.getOtherAccountTypeName());
        }
        withdrawBill.setWithdrawChannel(withdrawChannel);
        withdrawBill.setWithdrawType(applyWithdrawReqDTO.getWithdrawType());
        withdrawBill.setStatus(WithdrawStatusEnum.UNDERWAY.getIndex());
        withdrawBill.setCreateTime(new Date());
        withdrawBill.setOrgId(applyWithdrawReqDTO.getOrgId());
        withdrawBill.setMerchantId(applyWithdrawReqDTO.getMerchantId());
        save(withdrawBill);
        return withdrawBill;
    }


    /**
     * 生成提现交易记录
     */
    private void saveWithdrawTradeRecord(WithdrawBill withdrawBill) {
        TradeRecord tradeRecord = new TradeRecord();
        tradeRecord.setSerialNo(TradeUtils.buildSeqNo());
        tradeRecord.setTradeVoucherNo(withdrawBill.getWithdrawNo());
        tradeRecord.setMemberId(withdrawBill.getMemberId());
        tradeRecord.setMemberName(withdrawBill.getMemberName());
        tradeRecord.setAccountId(withdrawBill.getAccountId());
        tradeRecord.setOtherMemberId(withdrawBill.getMemberId());
        tradeRecord.setOtherMemberName(withdrawBill.getMemberName());
        tradeRecord.setOtherAccountId(withdrawBill.getAccountId());
        tradeRecord.setTradeType(TradeTypeEnum.WITHDRAWAL.getIndex());
        tradeRecord.setTradeTypeName(TradeTypeEnum.WITHDRAWAL.getText());
        tradeRecord.setTradeChannel(TradeChannelEnum.ACCOUNT.getIndex());
        tradeRecord.setAmount(withdrawBill.getAmount().abs().multiply(BigDecimal.valueOf(-1)));
        tradeRecord.setTradeSubject("账户提现");
        tradeRecord.setTradeContent("账户余额提现");
        tradeRecord.setFundFlowType(FundFlowTypeEnum.PAY.getIndex());
        tradeRecord.setTradeStatus(TradeStatusEnum.TRADE_STATUS_TRADING.getIndex());
        tradeRecord.setTradeTime(withdrawBill.getApplyTime());
        tradeRecord.setCreateTime(new Date());
        tradeRecord.setCreaterId(withdrawBill.getCreaterId());
        tradeRecord.setUpdaterId(withdrawBill.getCreaterId());
        tradeRecord.setOrgId(withdrawBill.getOrgId());
        tradeRecord.setMerchantId(withdrawBill.getMerchantId());
        tradeRecordService.save(tradeRecord);
    }


    /**
     * 校验提现
     */
    private ApplyWithdrawRespDTO validateWithdraw(ApplyWithdrawReqDTO applyWithdrawReqDTO, Account account) {
        String accountId = applyWithdrawReqDTO.getAccountId();
        BigDecimal applyAmount = applyWithdrawReqDTO.getAmount();
        if (account == null) {
            return ApplyWithdrawRespDTO.byFail(accountId, "申请账户不存在");
        }

        Member member = memberService.getById(applyWithdrawReqDTO.getMemberId());
        if (member == null) {
            return ApplyWithdrawRespDTO.byFail(accountId, "申请人不存在");
        }

        // 判断付款账户余额是否充足
        BigDecimal balanceAmount = account.getBalanceAmount();
        if (balanceAmount.compareTo(applyAmount) < 0) {
            return ApplyWithdrawRespDTO.byFail(accountId, "账户可提现余额不足");
        }

        return ApplyWithdrawRespDTO.bySuccess(accountId, "校验通过");
    }
}
